iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 10
1
Mobile Development

30天手滑用Google Flutter解鎖Hybrid App成就系列 第 10

30天Flutter手滑系列 - 無狀態與有狀態Widgets (Stateless & Stateful widgets)

  • 分享至 

  • xImage
  •  

結束上一篇30天Flutter手滑系列 - 導航與路由(Navigation & Routing),我們透過範例,示範了在路由跳轉時傳遞參數,但我們都使用的是StatelessWidget去達成目的。如果這時候有個輸入表單,那就需要用StatefulWidget才能做到。
在我們進入進階的狀態管理前,先來認識跟狀態有關的這兩個Widgets吧。

Stateless widget(無狀態 widget)

StatelessWidget在App初始化之後就不能改變,它是immutable。如果想要改變就得new一個新的StatelessWidget去做更換。

常見的StatelessWidget有:

  • Icon
  • Text
  • RaisedButton

延續之前的範例,我們來看一下其結構。
可以看到在整個Widget內都是使用靜態的Widget去做Navigation,過程中也不需要做任何狀態更新,應該是很好理解的。

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Page')),
      body: Center(
        child: RaisedButton(
          child: Text('Register'),
          onPressed: () {
            Navigator.of(context).pushNamed('/register',
                arguments: {'name': 'Raymond'}).then((value) {
              // 新增第二個變數arguments
              showDialog(
                  // 新增一個對話框,用來顯示回傳的值
                  context: context,
                  child: AlertDialog(
                    content: Text(value),
                  ));
            });
          },
        ),
      ),
    );
  }
}

Stateful widget(有狀態 widget)

StatefulWidget可以在App內無限次的被重繪集及更新狀態,它是mutable,需要重繪時可以調用setState(),去標記自己為dirty狀態,為下次更新做準備。

常見的StatefulWidget有:

  • Radio
  • Form
  • Checkbox

讓我們改寫範例,把傳遞參數部分透過使用者自行輸入名稱的方式去動態改變,因此我們需要改成Stateful Widget去操作這部分。

首先,定義一個StatefulWidget,然後把原本的MyHomePage變成一個私有的State,並繼承自MyHomePage這個StatefulWidget。
然後在_MyHomePageState中加入TextField,而要獲取TextField的值有兩種方法,透過TextEditingController,或是onChanged回傳,在這我用前者。
定義了controller後就可以獲取TextField中的值,因此在原本Navigation的參數部分,就可以直接引用controller的值了。

class MyHomePage extends StatefulWidget {   // 把MyHomePage設為一個StatefulWidget
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {      // 定義一個私有的Class,繼承自MyHomePage
  final TextEditingController _controller = TextEditingController();  // 定義一個controler

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Page')),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            width: 200.0,
            margin: EdgeInsets.only(bottom: 10),
            child: TextField(
              controller: _controller,    // 利用controller去獲取TextField的值
            ),
          ),
          RaisedButton(
            child: Text('Register'),
            onPressed: () {
              Navigator.of(context).pushNamed('/register',
                  arguments: {'name': _controller.text}).then((value) {   // 參數接收來自TextField controller的值
                // 新增第二個變數arguments
                showDialog(
                    // 新增一個對話框,用來顯示回傳的值
                    context: context,
                    child: AlertDialog(
                      content: Text(value),
                    ));
              });
            },
          )
        ],
      )),
    );
  }
}

範例展示:
https://upload.cc/i1/2019/09/17/UpnGVk.gif


Stateful與Stateless注意事項

  • 盡可能用Stateless。
  • Stateful Wigets盡量在越低層級的節點使用,避免過多不必要的重build。
  • setState((){})會觸發State.build,如果你的觸發是在根節點,會造成所有Widgets被重build,會是個效能問題。
  • 需要重build的Widget,盡量節點數越少越好。

總結

結束了10天基礎的UI Widgets介紹,明天會開始介紹較為進階的狀態管理(State Management)。


參考資料

https://flutter.dev/docs/development/ui/interactive
https://lizhaoxuan.github.io/2019/01/02/Flutter-%E4%BD%A0%E8%BF%98%E5%9C%A8%E6%BB%A5%E7%94%A8StatefulWidget%E5%90%97/
https://medium.com/flutter-community/flutter-stateful-vs-stateless-db325309deae


上一篇
30天Flutter手滑系列 - 導航與路由(Navigation & Routing)
下一篇
30天Flutter手滑系列 - 狀態管理 (State Management)
系列文
30天手滑用Google Flutter解鎖Hybrid App成就30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chichi
iT邦新手 2 級 ‧ 2019-09-30 08:14:33

盡量在子節點使用 Stateful。有點不懂 XD

這邊我稍微改一下語句,基本上應該是跟第三點有關XD
盡量減少setState重build的wigets數量是比較理想的,所以如果有狀態需要更新,盡量在越低層級的節點去做更新比較好。
如下圖,橘色框的重build的wigets會比紅色框內的少。
https://ithelp.ithome.com.tw/upload/images/20190930/20120028Iv7FPhRGnZ.png

我要留言

立即登入留言